home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / Resources / CutePDF 2.3 / converter.exe / GNUGS / GS_SETPD.PS < prev    next >
Text File  |  2003-04-01  |  25KB  |  777 lines

  1. %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This software is provided AS-IS with no warranty, either express or
  3. % implied.
  4. % This software is distributed under license and may not be copied,
  5. % modified or distributed except as expressly authorized under the terms
  6. % of the license contained in the file LICENSE in this distribution.
  7. % For more information about licensing, please refer to
  8. % http://www.ghostscript.com/licensing/. For information on
  9. % commercial licensing, go to http://www.artifex.com/licensing/ or
  10. % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
  12.  
  13. % $Id: gs_setpd.ps,v 1.8.2.2.2.1 2003/03/31 13:02:22 giles Exp $
  14. % The current implementation of setpagedevice has the following limitations:
  15. %    - It doesn't attempt to "interact with the user" for Policy = 2.
  16.  
  17. languagelevel 1 .setlanguagelevel
  18. level2dict begin
  19.  
  20. % ---------------- Redefinitions ---------------- %
  21.  
  22. % Redefine .beginpage and .endpage so that they call BeginPage and
  23. % EndPage respectively if appropriate.
  24.  
  25. % We have to guard against the BeginPage procedure not popping its operand.
  26. % This is really stupid, but the Genoa CET does it.
  27. /.beginpage {        % - .beginpage -
  28.   .currentshowpagecount {
  29.     .currentpagedevice pop
  30.     dup null ne { /BeginPage .knownget } { pop false } ifelse {
  31.         % Stack: ... pagecount proc
  32.        count 2 .execn
  33.         % Stack: ... ..???.. oldcount
  34.        count 1 add exch sub { pop } repeat
  35.     } {
  36.       pop
  37.     } ifelse
  38.   } if
  39. } bind odef
  40.  
  41. % Guard similarly against EndPage not popping its operand.
  42. /.endpage {        % <reason> .endpage <print_bool>
  43.   .currentshowpagecount {
  44.     1 index .currentpagedevice pop
  45.     dup null ne { /EndPage .knownget } { pop false } ifelse {
  46.         % Stack: ... reason pagecount reason proc
  47.       count 2 .execn
  48.         % Stack: ... ..???.. print oldcount
  49.       count 2 add exch sub { exch pop } repeat
  50.     } {
  51.       pop pop 2 ne
  52.     } ifelse
  53.   } {
  54.     2 ne
  55.   } ifelse
  56. } bind odef
  57.  
  58. % Define interpreter callouts for handling gstate-saving operators,
  59. % to make sure that they create a page device dictionary for use by
  60. % the corresponding gstate-restoring operator.
  61. % We'd really like to avoid the cost of doing this, but we don't see how.
  62. % The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
  63. % %copygstatepagedevice, and %currentgstatepagedevice are known to the
  64. % interpreter.
  65.  
  66. (%gsavepagedevice) cvn
  67.  { currentpagedevice pop gsave
  68.  } bind def
  69.  
  70. (%savepagedevice) cvn
  71.  { currentpagedevice pop save
  72.  } bind def
  73.  
  74. (%gstatepagedevice) cvn
  75.  { currentpagedevice pop gstate
  76.  } bind def
  77.  
  78. (%copygstatepagedevice) cvn
  79.  { currentpagedevice pop copy
  80.  } bind def
  81.  
  82. (%currentgstatepagedevice) cvn
  83.  { currentpagedevice pop currentgstate
  84.  } bind def
  85.  
  86. % Define interpreter callouts for handling gstate-restoring operators
  87. % when the current page device needs to be changed.
  88. % The names %grestorepagedevice, %grestoreallpagedevice,
  89. % %restorepagedevice, %restore1pagedevice, and %setgstatepagedevice
  90. % are known to the interpreter.
  91.  
  92. /.installpagedevice
  93.  {    % Since setpagedevice doesn't create new device objects,
  94.     % we must (carefully) reinstall the old parameters in
  95.     % the same device.
  96.    .currentpagedevice pop null currentdevice null .trysetparams
  97.    dup type /booleantype eq
  98.     { pop pop }
  99.     {        % This should never happen!
  100.       DEBUG { (Error in .trysetparams!) = pstack flush } if
  101.       cleartomark pop pop pop
  102.       /.installpagedevice cvx /rangecheck signalerror
  103.     }
  104.    ifelse pop pop
  105.     % A careful reading of the Red Book reveals that an erasepage
  106.     % should occur, but *not* an initgraphics.
  107.    erasepage .beginpage
  108.  } bind def
  109.  
  110. /.uninstallpagedevice
  111.  { 2 .endpage { .currentnumcopies false .outputpage } if
  112.    nulldevice
  113.  } bind def
  114.  
  115. (%grestorepagedevice) cvn
  116.  { .uninstallpagedevice grestore .installpagedevice
  117.  } bind def
  118.  
  119. (%grestoreallpagedevice) cvn
  120.  { .uninstallpagedevice grestore .installpagedevice grestoreall
  121.  } bind def
  122.  
  123. (%restore1pagedevice) cvn
  124.  { .uninstallpagedevice grestore .installpagedevice restore
  125.  } bind def
  126.  
  127. (%restorepagedevice) cvn
  128.  { .uninstallpagedevice restore .installpagedevice
  129.  } bind def
  130.  
  131. (%setgstatepagedevice) cvn
  132.  { .uninstallpagedevice setgstate .installpagedevice
  133.  } bind def
  134.  
  135. % Redefine .currentnumcopies so it consults the NumCopies device parameter.
  136. /.numcopiesdict mark
  137.   /NumCopies dup
  138. .dicttomark readonly def
  139.  
  140. /.currentnumcopies
  141.  { currentdevice //.numcopiesdict .getdeviceparams
  142.    dup type /integertype eq
  143.     { exch pop exch pop }
  144.     { cleartomark #copies }
  145.    ifelse
  146.  } bind odef
  147.  
  148. % Redefine .currentpagedevice and .setpagedevice so they convert between
  149. % null and a fixed empty directionary.
  150. /.nullpagedevice 0 dict readonly def
  151. /.currentpagedevice {
  152.   //.currentpagedevice exch dup null eq { pop //.nullpagedevice } if exch
  153. } bind odef
  154. /.setpagedevice {
  155.   dup //.nullpagedevice eq { pop null } if //.setpagedevice
  156. } bind odef
  157.  
  158. % ---------------- Auxiliary definitions ---------------- %
  159.  
  160. % Define the required attributes of all page devices, and their default values.
  161. % We don't include attributes such as .MediaSize, which all devices
  162. % are guaranteed to supply on their own.
  163. /.defaultpolicies mark
  164.   /PolicyNotFound 1
  165.   /PageSize 0
  166.   /PolicyReport {
  167.     dup /.LockSafetyParams known {
  168.     % Only possible error is invalidaccess
  169.       /setpagedevice .systemvar /invalidaccess signalerror
  170.     }
  171.     if
  172.     pop
  173.   } bind
  174. .dicttomark readonly def
  175. % Note that the values of .requiredattrs are executed, not just fetched.
  176. /.requiredattrs mark
  177.   /PageDeviceName null
  178.   /PageOffset [0 0] readonly
  179. % We define InputAttributes and OutputAttributes with a single
  180. % dummy media type that handles pages of any size.
  181. % Devices that care will override this.
  182.   /InputAttributes {
  183.     mark 0
  184.     % Since sizes match within 5 user units, we need to set the smallest
  185.     % PageSize to 6 units so that [0 0] will fail.
  186.     mark /PageSize [6 dup 16#7ffff dup] .dicttomark
  187.     .dicttomark
  188.   }
  189.   (%MediaSource) 0
  190.   /OutputAttributes {
  191.     mark 0 mark .dicttomark readonly .dicttomark
  192.   }
  193.   (%MediaDestination) 0
  194.   /Install {{.callinstall}} bind
  195.   /BeginPage {{.callbeginpage}} bind
  196.   /EndPage {{.callendpage}} bind
  197.   /Policies .defaultpolicies
  198. .dicttomark readonly def
  199.  
  200. % Define currentpagedevice so it creates the dictionary on demand if needed,
  201. % adding all the required entries defined just above.
  202. % We have to deal specially with entries that the driver may change
  203. % on its own.
  204. /.dynamicppkeys mark
  205.   /.MediaSize dup        % because it changes when PageSize is set
  206.   /PageCount dup
  207. .dicttomark readonly def
  208. /.makecurrentpagedevice {    % - .makecurrentpagedevice <dict>
  209.   currentdevice null .getdeviceparams
  210.     % Make the dictionary large enough to add defaulted entries.
  211.   counttomark 2 idiv .requiredattrs length add dict
  212.   counttomark 2 idiv { dup 4 2 roll put } repeat exch pop
  213.     % Add any missing required attributes.
  214.     % Make a writable and (if possible) local copy of any default
  215.     % dictionaries, to work around a bug in the output of WordPerfect,
  216.     % which assumes that these dictionaries are writable and local.
  217.   .currentglobal exch dup gcheck .setglobal
  218.   .requiredattrs {
  219.     2 index 2 index known {
  220.       pop pop
  221.     } {
  222.       exec 2 index 3 1 roll put
  223.     } ifelse
  224.   } forall exch .setglobal
  225.   dup .setpagedevice
  226. } bind def
  227. /currentpagedevice {
  228.   .currentpagedevice {
  229.     dup length 0 eq {
  230.       pop .makecurrentpagedevice
  231.     } {
  232.         % If any of the dynamic keys have changed,
  233.         % we must update the page device dictionary.
  234.       currentdevice //.dynamicppkeys .getdeviceparams .dicttomark {
  235.         % Stack: current key value
  236.         2 index 2 index .knownget { 1 index ne } { true } ifelse
  237.          { 2 index wcheck not
  238.         {    % This is the first entry being updated.
  239.             % Copy the dictionary to make it writable.
  240.           3 -1 roll
  241.           currentglobal 1 index dup gcheck currentglobal and setglobal
  242.           length dict exch setglobal .copydict
  243.           3 1 roll
  244.         }
  245.            if
  246.            2 index 3 1 roll put
  247.          }
  248.          { pop pop
  249.          }
  250.         ifelse
  251.       } forall
  252.         % If the dictionary was global and is now local, copy
  253.         % any global subsidiary dictionaries to local VM.  This
  254.         % too is to work around the Word Perfect bug (see above).
  255.       dup gcheck not {
  256.     dup {
  257.       dup type /dicttype eq { dup gcheck } { false } ifelse {
  258.         % Copy-on-write, see above.
  259.         2 index wcheck not {
  260.           3 -1 roll dup length dict .copydict
  261.           3 1 roll
  262.         } if
  263.         .copytree 2 index 3 1 roll put
  264.       } {
  265.         pop pop
  266.       } ifelse
  267.     } forall
  268.       } if
  269.         % We would like to do a .setpagedevice so we don't keep
  270.         % re-creating the dictionary.  Unfortunately, the effect
  271.         % of this is that if any dynamic key changes (PageCount
  272.         % in particular), we will do the equivalent of a
  273.         % setpagedevice at the next restore or grestore.
  274.         % Therefore, we make the dictionary read-only, but
  275.         % we don't store it away.  I.e., NOT:
  276.         % dup wcheck { .setpagedevice .currentpagedevice pop } if
  277.       readonly
  278.     } ifelse
  279.   } if
  280. } bind odef
  281.  
  282. % Copy a dictionary recursively.
  283. /.copytree {    % <dict> .copytree <dict'>
  284.   dup length dict exch {
  285.     dup type /dicttype eq { .copytree } if 2 index 3 1 roll put
  286.   } forall
  287. } bind def
  288.  
  289. % The implementation of setpagedevice is quite complex.  Currently,
  290. % everything but the media matching algorithm is implemented here.
  291.  
  292. % By default, we only present the requested changes to the device,
  293. % but there are some parameters that require special merging action.
  294. % Define those parameters here, with the procedures that do the merging.
  295. % The procedures are called as follows:
  296. %    <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
  297. /.mergespecial mark
  298.   /InputAttributes
  299.    { dup null eq
  300.       { pop null
  301.       }
  302.       { 3 copy pop .knownget
  303.      { dup null eq
  304.         { pop dup length dict }
  305.         { dup length 2 index length add dict .copydict }
  306.        ifelse
  307.      }
  308.      { dup length dict
  309.      }
  310.         ifelse .copydict readonly
  311.       }
  312.      ifelse
  313.    } bind
  314.   /OutputAttributes 1 index
  315.   /Policies
  316.     { 3 copy pop .knownget
  317.        { dup length 2 index length add dict .copydict }
  318.        { dup length dict }
  319.       ifelse copy readonly
  320.     } bind
  321. .dicttomark readonly def
  322.  
  323. % Define the keys used in input attribute matching.
  324. /.inputattrkeys [
  325.   /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet
  326.     % The following are documented in Adobe's supplement for v2017.
  327.   /LeadingEdge /MediaClass
  328. ] readonly def
  329. % Define other keys used in media selection.
  330. /.inputselectionkeys [
  331.   /MediaPosition /Orientation
  332. ] readonly def
  333.  
  334. % Define the keys used in output attribute matching.
  335. /.outputattrkeys [
  336.   /OutputType
  337. ] readonly def
  338.  
  339. % Define all the parameters that should always be copied to the merged
  340. % dictionary.
  341. /.copiedkeys [
  342.   /OutputDevice
  343.   .mergespecial { pop } forall
  344.   .inputattrkeys aload pop
  345.   .inputselectionkeys aload pop
  346.   .outputattrkeys aload pop
  347. ] readonly def
  348.  
  349. % Define the parameters that should not be presented to the device.
  350. % The procedures are called as follows:
  351. %    <merged> <key> <value> -proc-
  352. % The procedure leaves all its operands on the stack and returns
  353. % true iff the key/value pair should be presented to .putdeviceparams.
  354. /.presentspecial mark
  355.   .dynamicppkeys { pop false } forall
  356.             % We must ignore an explicit request for .MediaSize,
  357.             % because media matching always handles this.
  358.   /.MediaSize false
  359.   /Name false
  360.   /OutputDevice false
  361.   /PageDeviceName false
  362.   /PageOffset false
  363.   /PageSize false        % obsolete alias for .MediaSize
  364.   /InputAttributes false
  365.   .inputattrkeys
  366.     { dup /PageSize eq
  367.        { pop }
  368.        { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }
  369.       ifelse
  370.     }
  371.   forall
  372.   .inputselectionkeys { false } forall
  373.   /OutputAttributes false
  374.   .outputattrkeys
  375.     { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }
  376.   forall
  377.   /Install false
  378.   /BeginPage false
  379.   /EndPage false
  380.   /Policies false
  381.     % Our extensions:
  382.   /HWColorMap
  383.     {            % HACK: don't transmit the color map, because
  384.             % window systems can change the color map on their own
  385.             % incrementally.  Someday we'll have a better
  386.             % solution for this....
  387.       false
  388.     }
  389.   /ViewerPreProcess false
  390. .dicttomark readonly def
  391.  
  392. % Define access to device defaults.
  393. /.defaultdeviceparams
  394.  { finddevice null .getdeviceparams
  395.  } bind def
  396.  
  397. % Select media (input or output).  The hard work is done in an operator:
  398. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
  399. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia false
  400. %    <pagedict> null <policydict> <keys> .matchmedia null true
  401. /.selectmedia        % <orig> <request> <merged> <failed>     <-- retained
  402.             %   <attrdict> <policydict> <attrkeys> <mediakey>
  403.             %   .selectmedia
  404.  { 5 index 5 -2 roll 4 index .matchmedia
  405.         % Stack: orig request merged failed attrkeys mediakey
  406.         %   (key true | false)
  407.     { 4 index 3 1 roll put pop
  408.     }
  409.     {    % Adobe's implementations have a "big hairy heuristic"
  410.     % to choose the set of keys to report as having failed the match.
  411.     % For the moment, we report any keys that are in the request
  412.     % and don't have the same value as in the original dictionary.
  413.       5 index 1 index .knownget
  414.        { 4 index 3 1 roll put }
  415.        { 3 index exch .undef }
  416.       ifelse
  417.        {    % Stack: <orig> <request> <merged> <failed> <attrkey>
  418.      3 index 1 index .knownget
  419.       { 5 index 2 index .knownget { ne } { pop true } ifelse }
  420.       { true }
  421.      ifelse        % Stack: ... <failed> <attrkey> <report>
  422.       { 2 copy /rangecheck put }
  423.      if pop
  424.        }
  425.       forall
  426.     }
  427.    ifelse
  428.  } bind def
  429.  
  430. % Apply Policies to any unprocessed failed requests.
  431. % As we process each request entry, we replace the error name
  432. % in the <failed> dictionary with the policy value,
  433. % and we replace the key in the <merged> dictionary with its prior value
  434. % (or remove it if it had no prior value).
  435. /.policyprocs mark
  436. % These procedures are called with the following on the stack:
  437. %   <orig> <merged> <failed> <Policies> <key> <policy>
  438. % They are expected to consume the top 2 operands.
  439. % NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
  440. % the same as 0, i.e., we signal an error.
  441.   0 {        % Set errorinfo and signal a configurationerror.
  442.     pop dup 4 index exch get 2 array astore
  443.     $error /errorinfo 3 -1 roll put
  444.     cleartomark
  445.     /setpagedevice load /configurationerror signalerror
  446.   } bind
  447.   1 {        % Roll back the failed request to its previous status.
  448. DEBUG { (Rolling back.) = pstack flush } if
  449.     3 index 2 index 3 -1 roll put
  450.     4 index 1 index .knownget
  451.      { 4 index 3 1 roll put }
  452.      { 3 index exch .undef }
  453.     ifelse
  454.   } bind
  455.   7 {        % For PageSize only, just impose the request.
  456.     1 index /PageSize eq
  457.      { pop pop 1 index /PageSize 7 put }
  458.      { .policyprocs 0 get exec }
  459.     ifelse
  460.   } bind
  461. .dicttomark readonly def
  462. /.applypolicies        % <orig> <merged> <failed> .applypolicies
  463.             %   <orig> <merged'> <failed'>
  464.  { 1 index /Policies get 1 index
  465.     { type /integertype eq
  466.        { pop        % already processed
  467.        }
  468.        { 2 copy .knownget not { 1 index /PolicyNotFound get } if
  469.             % Stack: <orig> <merged> <failed> <Policies> <key>
  470.             %   <policy>
  471.      .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
  472.        }
  473.       ifelse
  474.     }
  475.    forall pop
  476.  } bind def
  477.  
  478. % Prepare to present parameters to the device, by spreading them onto the
  479. % operand stack and removing any that shouldn't be presented.
  480. /.prepareparams        % <params> .prepareparams -mark- <key1> <value1> ...
  481.  { mark exch dup
  482.     {            % Stack: -mark- key1 value1 ... merged key value
  483.       .presentspecial 2 index .knownget
  484.        { exec { 3 -1 roll } { pop pop } ifelse }
  485.        { 3 -1 roll }
  486.       ifelse
  487.     }
  488.    forall pop
  489.  } bind def
  490.  
  491. % Put device parameters without resetting currentpagedevice.
  492. % (.putdeviceparams clears the current page device.)
  493. /.putdeviceparamsonly    % <device> <Policies|null> <require_all> -mark-
  494.             %   <key1> <value1> ... .putdeviceparamsonly
  495.             % On success: <device> <eraseflag>
  496.             % On failure: <device> <Policies|null> <req_all> -mark-
  497.             %   <key1> <error1> ...
  498.  { .currentpagedevice
  499.     { counttomark 4 add 1 roll .putdeviceparams
  500.       dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
  501.       .setpagedevice
  502.     }
  503.     { pop .putdeviceparams
  504.     }
  505.    ifelse
  506.  } bind def
  507.  
  508. % Try setting the device parameters from the merged request.
  509. /.trysetparams        % <merged> <(ignored)> <device> <Policies>
  510.             %   .trysetparams
  511.  { true 4 index .prepareparams
  512.             % Add the computed .MediaSize.
  513.             % Stack: merged (ignored) device Policies -true-
  514.             %   -mark- key1 value1 ...
  515.    counttomark 5 add index .computemediasize
  516.    exch pop exch pop /.MediaSize exch
  517. DEBUG { (Putting.) = pstack flush } if
  518.    .putdeviceparamsonly
  519. DEBUG { (Result of putting.) = pstack flush } if
  520.  } bind def
  521.  
  522. % Compute the media size and initial matrix from a merged request (after
  523. % media selection).
  524. /.computemediasize    % <request> .computemediasize
  525.             %   <request> <matrix> <[width height]>
  526.  { dup /PageSize get                    % requested page size
  527.    1 index /InputAttributes get
  528.      2 index (%MediaSource) get get /PageSize get    % media size
  529.                             % (may be a range)
  530.    2 index /Policies get
  531.      dup /PageSize .knownget
  532.       { exch pop } { /PolicyNotFound get } ifelse    % PageSize policy,
  533.                             % affects scaling
  534.    3 index /Orientation .knownget not { null } if
  535.    4 index /RollFedMedia .knownget not { false } if
  536.    matrix .matchpagesize not {
  537.         % This is a "can't happen" condition!
  538.      /setpagedevice load /rangecheck signalerror
  539.    } if
  540.    2 array astore
  541.  } bind def
  542.  
  543. % ---------------- setpagedevice itself ---------------- %
  544.  
  545. /setpagedevice
  546.  {        % We mustn't pop the argument until the very end,
  547.         % so that the pseudo-operator machinery can restore the stack
  548.         % if an error occurs.
  549.    mark 1 index currentpagedevice
  550.  
  551.         % Check whether we are changing OutputDevice;
  552.         % also handle the case where the current device
  553.         % is not a page device.
  554.         % Stack: mark <request> <current>
  555. DEBUG { (Checking.) = pstack flush } if
  556.  
  557.    dup /OutputDevice .knownget
  558.     {        % Current device is a page device.
  559.       2 index /OutputDevice .knownget
  560.        {    % A specific OutputDevice was requested.
  561.      2 copy eq
  562.       { pop pop null }
  563.       { exch pop }
  564.      ifelse
  565.        }
  566.        { pop null
  567.        }
  568.       ifelse
  569.     }
  570.     {        % Current device is not a page device.
  571.         % Use the default device.
  572.       1 index /OutputDevice .knownget not { .defaultdevicename } if
  573.     }
  574.    ifelse
  575.    dup null eq
  576.     { pop
  577.     }
  578.     { exch pop .defaultdeviceparams
  579.         % In case of duplicate keys, .dicttomark takes the entry
  580.         % lower on the stack, so we can just append the defaults here.
  581.       .requiredattrs { exec } forall .dicttomark
  582.     }
  583.    ifelse
  584.  
  585.         % Check whether a viewer wants to intervene.
  586.         % We must check both the request (which takes precedence)
  587.         % and the current dictionary.
  588.         % Stack: mark <request> <orig>
  589.    exch dup /ViewerPreProcess .knownget
  590.     { exec }
  591.     { 1 index /ViewerPreProcess .knownget { exec } if }
  592.    ifelse exch
  593.  
  594.         % Construct a merged request from the actual request plus
  595.         % any keys that should always be propagated.
  596.         % Stack: mark <request> <orig>
  597. DEBUG { (Merging.) = pstack flush } if
  598.  
  599.    exch 1 index length 1 index length add dict
  600.    .copiedkeys
  601.     {        % Stack: <orig> <request> <merged> <key>
  602.       3 index 1 index .knownget { 3 copy put pop } if pop
  603.     }
  604.    forall
  605.         % Stack: <orig> <request> <merged>
  606.    dup 2 index
  607.     {        % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
  608.       .mergespecial 2 index .knownget { exec } if
  609.       put dup
  610.     }
  611.    forall pop
  612.         % Hack: if FIXEDRESOLUTION is true, discard any attempt to
  613.         % change HWResolution.
  614.    FIXEDRESOLUTION { dup /HWResolution .undef } if
  615.         % Hack: if FIXEDMEDIA is true, discard any attempt to change
  616.         % PageSize or HWSize.
  617.    FIXEDMEDIA
  618.     { dup /PageSize 4 index /PageSize get put
  619.       dup /HWSize 4 index /HWSize get put
  620.     } if
  621.         % Hack: to work around some files that take a PageSize
  622.         % from InputAttributes and impose it, discard any attempt
  623.         % to set PageSize to a 4-element value.
  624.         % Stack: mark <orig> <request> <merged>
  625.     dup /PageSize .knownget {
  626.       length 2 ne {
  627.     dup /PageSize 4 index /PageSize get put
  628.       } if
  629.     } if
  630.  
  631.         % Select input and output media.
  632.         % Stack: mark <orig> <request> <merged>
  633. DEBUG { (Selecting.) = pstack flush } if
  634.  
  635.    0 dict    % <failed>
  636.    1 index /InputAttributes .knownget
  637.     { 2 index /Policies get
  638.       .inputattrkeys (%MediaSource) cvn .selectmedia
  639.     } if
  640.    1 index /OutputAttributes .knownget
  641.     { 2 index /Policies get
  642.       .outputattrkeys (%MediaDestination) cvn .selectmedia
  643.      } if
  644.    3 -1 roll 4 1 roll        % temporarily swap orig & request
  645.    .applypolicies
  646.    3 -1 roll 4 1 roll        % swap back
  647.  
  648.         % Construct the new device, and attempt to set its attributes.
  649.         % Stack: mark <orig> <request> <merged> <failed>
  650. DEBUG { (Constructing.) = pstack flush } if
  651.  
  652.    currentdevice .devicename 2 index /OutputDevice get eq
  653.     { currentdevice }
  654.     { 1 index /OutputDevice get finddevice }
  655.    ifelse
  656.         %**************** We should copy the device here,
  657.         %**************** but since we can't close the old device,
  658.         %**************** we don't.  This is WRONG.
  659.     %****************copydevice
  660.    2 index /Policies get
  661.    .trysetparams
  662.    dup type /booleantype ne
  663.     {        % The request failed.
  664.         % Stack: ... <orig> <request> <merged> <failed> <device>
  665.         %   <Policies> true mark <name> <errorname> ...
  666. DEBUG { (Recovering.) = pstack flush } if
  667.       counttomark 4 add index
  668.       counttomark 2 idiv { dup 4 -2 roll put } repeat
  669.       pop pop pop
  670.         % Stack: mark ... <orig> <request> <merged> <failed> <device>
  671.         %   <Policies>
  672.       6 2 roll 3 -1 roll 4 1 roll
  673.       .applypolicies
  674.       3 -1 roll 4 1 roll 6 -2 roll
  675.       .trysetparams        % shouldn't fail!
  676.       dup type /booleantype ne
  677.        { 2 { counttomark 1 add 1 roll cleartomark } repeat
  678.          /setpagedevice load exch signalerror
  679.        }
  680.       if
  681.     }
  682.    if
  683.  
  684.         % The attempt succeeded.  Install the new device.
  685.         % Stack: mark ... <merged> <failed> <device> <eraseflag>
  686. DEBUG { (Installing.) = pstack flush } if
  687.  
  688.    pop 2 .endpage
  689.     { 1 true .outputpage
  690.       (>>setpagedevice, press <return> to continue<<\n) .confirm
  691.     }
  692.    if
  693.         % .setdevice clears the current page device!
  694.    .currentpagedevice pop exch
  695.    .setdevice pop
  696.    .setpagedevice
  697.  
  698.         % Merge the request into the current page device,
  699.         % unless we're changing the OutputDevice.
  700.         % Stack: mark ... <merged> <failed>
  701.    exch currentpagedevice dup length 2 index length add dict
  702.         % Stack: mark ... <failed> <merged> <current> <newdict>
  703.    2 index /OutputDevice .knownget {
  704.      2 index /OutputDevice .knownget not { null } if eq
  705.    } {
  706.      true
  707.    } ifelse {
  708.         % Same OutputDevice, merge the dictionaries.
  709.      .copydict
  710.    } {
  711.         % Different OutputDevice, discard the old dictionary.
  712.      exch pop
  713.    } ifelse .copydict
  714.         % Initialize the default matrix, taking media matching
  715.         % into account.
  716.    .computemediasize pop initmatrix concat
  717.    dup /PageOffset .knownget
  718.     {        % Translate by the given number of 1/72" units in device X/Y.
  719.       dup 0 get exch 1 get
  720.       2 index /HWResolution get dup 1 get exch 0 get
  721.       4 -1 roll mul 72 div   3 1 roll mul 72 div
  722.       idtransform translate
  723.     }
  724.    if
  725.         % We must install the new page device dictionary
  726.         % before calling the Install procedure.
  727.   dup .setpagedevice
  728.   .setdefaultscreen    % Set the default screen before calling Install.
  729.   dup /Install .knownget {
  730.     { .execinstall } stopped { .postinstall stop } { .postinstall } ifelse
  731.   } {
  732.     .postinstall
  733.   } ifelse
  734. } odef
  735.  
  736. % We break out the code after calling the Install procedure into a
  737. % separate procedure, since it is executed even if Install causes an error.
  738. % By making .execinstall a separate operator procedure, we get the stacks
  739. % restored if it fails.
  740.  
  741. /.execinstall {        % <proc> .execinstall -
  742.     % Because the interpreter optimizes tail calls, we can't just let
  743.     % the body of this procedure be 'exec', because that would lose
  744.     % the stack protection that is the whole reason for having the
  745.     % procedure in the first place.  We hack this by adding a couple
  746.     % of extra tokens to ensure that the operator procedure is still
  747.     % on the stack during the exec.
  748.   exec
  749.   0 pop    % See above.
  750. } odef
  751. /.postinstall {        % mark ... <failed> <merged> .postinstall -
  752.    matrix currentmatrix .setdefaultmatrix
  753.         % Erase and initialize the page.
  754.    erasepage initgraphics
  755.    .beginpage
  756.  
  757.         % Clean up, calling PolicyReport if needed.
  758.         % Stack: mark ... <failed> <merged>
  759. DEBUG { (Finishing.) = pstack flush } if
  760.  
  761.    exch dup length 0 ne
  762.     { 1 index /Policies get /PolicyReport get
  763.       counttomark 1 add 2 roll cleartomark
  764.       exec
  765.     }
  766.     { cleartomark
  767.     }
  768.    ifelse pop
  769.  
  770. } odef
  771.  
  772. end                % level2dict
  773. .setlanguagelevel
  774.